Skip to content

1. QMI8658 A-axis 6D 陀螺仪传感器数据手册

MPU6050原理图替代QMI8658MPU6050原理图替代QMI8658 AD0一般接地 所以I2C 7位address为0x6B

BH1750_AHT30_BMP280_QMI8658_ESP32S3接线图

如果无法预览,请点击 此处下载 QMI8658A DatasheetRev1.0 数据手册 PDF 文件

1. 产品概述

QMI8658 是一款低噪声、宽带宽的 6D 惯性测量单元(IMU),集成 3 轴陀螺仪和 3 轴加速度计,适用于消费电子和工业应用。其核心优势包括低延迟、小尺寸封装及丰富的运动检测功能,可通过 I3C、I2C 或 SPI 接口与主机通信。

2. 关键特性

  • 低噪声性能:陀螺仪噪声密度 15 mdps/√Hz,加速度计噪声密度 150 µg/√Hz。
  • 宽动态范围:陀螺仪量程 ±16°/s~±2048°/s,加速度计量程 ±2g~±16g。
  • 多接口支持:MIPI™ I3C、I2C、3 线/4 线 SPI(从机模式)。
  • 小尺寸封装:2.5×3.0×0.86 mm 14 引脚 LGA。
  • 低功耗管理:支持低功耗模式,集成 1536 字节 FIFO 以降低系统功耗。
  • 运动检测功能:内置计步器、敲击检测(Tap)、任意运动(Any-Motion)、无运动(No-Motion)及显著运动(Significant-Motion)检测。

3. 应用领域

QMI8658 适用于多种场景,包括:

  • 智能手机、游戏控制器、遥控器。
  • 机器人吸尘器、电动自行车/滑板车。
  • 蓝牙耳机、汽车安全系统、玩具。
  • 横竖屏显示控制。

4. 核心功能模块

4.1 FIFO 数据缓冲

  • 1536 字节 FIFO,支持“FIFO”(满时停止写入)和“Stream”(满时覆盖旧数据)模式。
  • 可配置水印中断,支持批量读取传感器数据以降低系统功耗。

4.2 运动检测

  • Any-Motion/No-Motion:通过加速度斜率阈值和持续时间检测运动状态,支持多轴逻辑(OR/AND)配置。
  • Significant-Motion:基于 Any-Motion 和 No-Motion 事件,检测持续显著运动。
  • Tap 检测:支持单/双击识别,可配置峰值阈值、窗口时间及轴优先级。

4.3 计步器

  • 基于加速度峰值检测步数,支持步长阈值、超时窗口及计数精度配置,步数通过 24 位寄存器输出。

4.4 唤醒运动(WoM)

  • 超低功耗模式,通过运动检测触发中断唤醒主机,支持阈值、中断引脚及初始电平配置。

5. 接口与配置

  • 串行接口
    • SPI:3 线/4 线模式,最高 15 MHz。
    • I2C:标准/快速模式,最高 400 kHz。
    • I3C:标准数据速率(SDR)最高 12.5 MHz。
  • 寄存器控制:通过 CTRL1-CTRL9 寄存器配置传感器模式、ODR、滤波器及中断。

2. QMI8658 6轴陀螺仪传感器代码实现(ESP-IDF V6.0)

2.1 如何编写QMI8658 I2C驱动的具体流程(ESP-IDF v6.0)?

2.1.1 初始化 I2C 总线

  1. 使用 driver/i2c_master.h 创建 I2C 总线句柄。配置 SCL (GPIO 42) 和 SDA (GPIO 40),波特率设为 100kHz 或 400kHz。

2.1.2 添加设备并验证 ID

  1. 向总线添加 QMI8658 设备(地址 0x6B,后续核实)。
  2. 读取 WHO_AM_I 寄存器(地址 0x00)。如果返回值为 0x05,说明传感器连接正常。

2.1.3 配置传感器(针对陀螺仪及加速度计 Page30)

    1. 写入 CTRL1 0x02 (0x40):设置 小端字节序以及地址自动递增(建议设置为1,方便后续突发读取),以及中断引脚配置(如果不使用中断可先保持默认)。ESP32-S3为小端芯片。
  1. 写入 CTRL2 0x03 (0x25):设置加速度计的输出数据速率 (ODR) 和 量程 (FSR)。加速度计: 8g, 250Hz。
  2. 写入 CTRL3 0x04 (0x65):设置陀螺仪的输出数据速率 (ODR) 和 量程 (FSR)。陀螺仪: 1024dps, 224.2Hz。
  3. 写入 CTRL5 0x06 (0x00):可选配置低通滤波器。建议启用,以抑制高频噪声(本次关闭)。

2.1.4 启用传感器(Page32)

  1. 写入 CTRL7 0x08 (0x03):将 gEN 位 置 1,将aEN 位0 置为1,启用陀螺仪,Enable Accelerometer。

注意:配置寄存器(如 CTRL1~CTRL5CTRL7)建议在传感器停止状态下写入(即 aEN=0, gEN=0),配置完成后再启用。

2.1.5 轮询数据准备就绪标志 (DRDY——Page34)

  1. 在 while(1) 循环中,轮询 STATUS0 (0x2E) 寄存器。
  2. 检查 bit1 (gDA)和(aDA)。当 gDA=1 以及 aDA=1 时,表示新的陀螺仪和加速度计数据已准备好。gyroscope data and accelerometer data。

2.1.6 读取原始数据(Page 36)

  1. 一旦 gDA=1 以及 aDA=1 变为 1,连续读取 6 个字节 accelerometer 从 0x35 LSB 低字节序AX_L<7:0>(gyroscope 从寄存器 0x3B 开始,即 GX_L)。
  2. 如果已设置 CTRL1 中的 ADDR_AI=1,则寄存器地址会自动递增,一次 i2c_master_transmit_receive 即可完成。

2.1.7 数据转换(计算物理值)

  1. 组合 [高8位 << 8 | 低8位] 得到 int16_t 原始值。
  2. 根据量程计算:角度速率(dps) = 原始值 * FSR / 32768
  3. 以 ±256 dps 为例,计算公式为:原始值 * 256 / 32768 = 原始值 / 128

2.2 需要重点关注的关键指令/寄存器

寄存器地址名称功能必须关注点
0x00WHO_AM_I芯片ID应返回 0x05,用于验证设备
0x02CTRL1接口控制bit6: ADDR_AI 必须置1以支持突发读取;bit4-3 用于启用中断引脚
0x03CTRL2加速度计配置陀螺仪、加速度计、大小端字节序
0x04CTRL3陀螺仪配置必须配置 gODR[3:0] 和 gFS[2:0]
0x06CTRL5滤波配置建议设置 gLPF_EN=1 并选择合适的 gLPF_MODE
0x08CTRL7传感器启用必须将 gEN 置1
0x2ESTATUS0数据状态必须轮询 gDA (bit1),用于判断数据是否更新
0x3B~0x40GX_L~GZ_H陀螺仪数据6个寄存器连续存储 X, Y, Z 轴数据

2.3 QMI8658 的 I2C 地址(源自数据手册第82页 16.3.1节)

QMI8658A的 ADO 引脚接地,因此地址为 0x6B

ADO (SA0) 状态7位 I2C 地址写地址 (8位)读地址 (8位)
接地 (GND)0x6B (0b1101011)0xD60xD7
接 VCC 或悬空 (默认内部上拉)0x6A (0b1101010)0xD40xD5

QMI8658_I2C通信流程QMI8658_I2C通信流程

2.4 代码实现

C
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2c_master.h"
#include "esp_log.h"

static const char *TAG = "QMI8658A";

// 引脚定义 (请根据你的实际接线修改)
#define I2C_MASTER_SCL_IO          GPIO_NUM_42
#define I2C_MASTER_SDA_IO          GPIO_NUM_41
#define I2C_MASTER_FREQ_HZ         400000         // 400kHz
#define I2C_PORT                   I2C_NUM_0
#define QMI8658_ADDR               0x6B           // AD0 = connected GND, 7-bit地址
#define I2C_TIMEOUT_MS             1000

// 寄存器地址
#define REG_WHO_AM_I               0x00
#define REG_CTRL1                  0x02
#define REG_CTRL2                  0x03
#define REG_CTRL3                  0x04
#define REG_CTRL5                  0x06
#define REG_CTRL7                  0x08
#define REG_STATUS0                0x2E
#define REG_ACC_DATA               0x35
#define REG_GYRO_DATA              0x3B
#define REG_RESET                  0x60

// 全局I2C句柄
static i2c_master_bus_handle_t bus_handle;
static i2c_master_dev_handle_t dev_handle;

// 写寄存器
static esp_err_t qmi8658_write_reg(uint8_t reg_addr, uint8_t data) {
    uint8_t write_buf[2] = {reg_addr, data};
    return i2c_master_transmit(dev_handle, write_buf, sizeof(write_buf), I2C_TIMEOUT_MS);
}

// 读寄存器
static esp_err_t qmi8658_read_reg(uint8_t reg_addr, uint8_t *data, size_t len) {
    return i2c_master_transmit_receive(dev_handle, &reg_addr, 1, data, len, I2C_TIMEOUT_MS);
}

void app_main(void) {
    ESP_LOGI(TAG, "启动 QMI8658A 简化测试");

    // 1. 初始化 I2C 主机总线
    i2c_master_bus_config_t bus_config = {
        .clk_source = I2C_CLK_SRC_DEFAULT,
        .i2c_port = I2C_PORT,
        .scl_io_num = I2C_MASTER_SCL_IO,
        .sda_io_num = I2C_MASTER_SDA_IO,
        .glitch_ignore_cnt = 7,
        .flags.enable_internal_pullup = false, // 关闭内部上拉
    };
    ESP_ERROR_CHECK(i2c_new_master_bus(&bus_config, &bus_handle));

    // 2. 添加设备
    i2c_device_config_t dev_config = {
        .dev_addr_length = I2C_ADDR_BIT_LEN_7,
        .device_address = QMI8658_ADDR,
        .scl_speed_hz = I2C_MASTER_FREQ_HZ,
    };
    ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_config, &dev_handle));

    // 3. 检查 WHO_AM_I
    uint8_t who_am_i = 0;
    ESP_ERROR_CHECK(qmi8658_read_reg(REG_WHO_AM_I, &who_am_i, 1));
    if (who_am_i != 0x05) {
        ESP_LOGE(TAG, "WHO_AM_I 错误: 0x%02X", who_am_i);
        vTaskDelete(NULL);
    } else {
        ESP_LOGI(TAG, "✅ QMI8658A 连接成功!");
    }

    // 4. 软件复位
    qmi8658_write_reg(REG_RESET, 0xB0);
    vTaskDelay(pdMS_TO_TICKS(10));

    // 5. 基础配置 (1024dps量程, 250Hz, 开启加速度计和陀螺仪)
    qmi8658_write_reg(REG_CTRL1, 0x40); // 地址自增, 小端字节序 (Little Endian) - 匹配 ESP32-S3
    qmi8658_write_reg(REG_CTRL2, 0x25); // 加速度计: 8g, 250Hz
    qmi8658_write_reg(REG_CTRL3, 0x65); // 陀螺仪: 1024dps, 224.2Hz
    qmi8658_write_reg(REG_CTRL5, 0x00); // 禁用低通滤波
    qmi8658_write_reg(REG_CTRL7, 0x03); // 使能传感器 (Bit0=ACC, Bit1=GYRO)
    vTaskDelay(pdMS_TO_TICKS(100));

    ESP_LOGI(TAG, "初始化完成,开始读取数据...");

    // 6. 循环读取数据
    while (1) {
        uint8_t status;
        qmi8658_read_reg(REG_STATUS0, &status, 1);
        
        // 检查 StatusS0: Bit0=加速度计数据就绪, Bit1=陀螺仪数据就绪
        // 0x03 = 0b00000011,表示两个传感器都有新数据
        if ((status & 0x03) == 0x03) {
            uint8_t raw_data[12];
            
            // 读取加速度计数据 (Register 0x35-0x3A): AX_L, AX_H, AY_L, AY_H, AZ_L, AZ_H
            qmi8658_read_reg(REG_ACC_DATA, raw_data, 12); // 连续读取加速度计和陀螺仪数据,利用地址自增功能
            
            // 读取陀螺仪数据 (Register 0x3B-0x40): GX_L, GX_H, GY_L, GY_H, GZ_L, GZ_H
            // qmi8658_read_reg(REG_GYRO_DATA, raw_data + 6, 6);


            // 解析原始数据 (小端字节序: 低字节_L在前,高字节_H在后)
            short acc[3], gyro[3];
            for (int i = 0; i < 3; i++) {
                // 加速度计: raw_data[0]=AX_L, raw_data[1]=AX_H, raw_data[2]=AY_L, ...
                acc[i] = (short)((raw_data[i*2+1] << 8) | raw_data[i*2]);
                
                // 陀螺仪: raw_data[6]=GX_L, raw_data[7]=GX_H, raw_data[8]=GY_L, ...
                gyro[i] = (short)((raw_data[6 + i*2+1] << 8) | raw_data[6 + i*2]);
            }

            // 转换为物理单位
            // 加速度计: 8g 量程, 16位有符号数范围 ±32768
            // 灵敏度 = 32768 / 8 = 4096 LSB/g
            float acc_x = (float)acc[0] / 4096.0f;
            float acc_y = (float)acc[1] / 4096.0f;
            float acc_z = (float)acc[2] / 4096.0f;
            
            // 陀螺仪: 1024dps 量程, 16位有符号数范围 ±32768
            // 灵敏度 = 32768 / 1024 = 32 LSB/dps
            float gyro_x = (float)gyro[0] / 32.0f;
            float gyro_y = (float)gyro[1] / 32.0f;
            float gyro_z = (float)gyro[2] / 32.0f;

            ESP_LOGI(TAG, "ACC(g): X=%+.3f Y=%+.3f Z=%+.3f | GYRO(dps): X=%+.2f Y=%+.2f Z=%+.2f", 
                     acc_x, acc_y, acc_z, gyro_x, gyro_y, gyro_z);
        }
        vTaskDelay(pdMS_TO_TICKS(100)); // 10Hz 采样率 (100ms间隔)
    }
}

觉醒,然后燎原。 © 2026 门主引擎